// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "header_generator.h"

using std::map;
using std::string;
using std::vector;

static const string add_attribute(map<string, string> attributes, const string& attribute) {
  auto ft = attributes.find(attribute);
  return (ft == attributes.end()) ? string() : ft->second;
}

static vector<int> collect_nonnull(const Syscall& sc) {
  vector<int> nonnull;
  int out_idx = static_cast<int>(sc.arg_spec.size());
  sc.for_each_return([&](const TypeSpec& type) {
    ++out_idx;
    if (!has_attribute("optional", type.attributes))
      nonnull.push_back(out_idx);
  });
  return nonnull;
}

bool HeaderGenerator::syscall(std::ofstream& os, const Syscall& sc) {
  constexpr uint32_t indent_spaces = 4u;

  for (const auto& name_prefix : name_prefixes_) {
    if (name_prefix.second(sc))
      continue;

    auto syscall_name = name_prefix.first + sc.name;

    os << function_prefix_;

    write_syscall_signature_line(os, sc, name_prefix.first, "\n" + string(indent_spaces, ' '),
                                 "\n" + string(indent_spaces, ' '),
                                 allow_pointer_wrapping_ && !sc.is_vdso(), no_args_type_);

    if (!allow_pointer_wrapping_) {
      const vector<int> nonnull = collect_nonnull(sc);
      if (!nonnull.empty()) {
        os << " __NONNULL((";
        for (int idx : nonnull) {
          os << idx << ", ";
        }
        os.seekp(-2, std::ios_base::end);
        os << "))";
      }
    }

    os << " ";

    // Writes attributes after arguments.
    for (const auto& attr : sc.attributes) {
      auto a = add_attribute(attributes_, attr);
      if (!a.empty())
        os << a << " ";
    }

    os.seekp(-1, std::ios_base::end);

    os << ";\n\n";
  }

  return os.good();
}
